package DataModel.LayoutManager;

import java.awt.Point;
import java.util.ArrayList;
import java.util.LinkedList;

import DataModel.CommonLibrary.CommonDefs.Layer;;

/**
 * Basic rectangle class. Contains rectangle position coordinates, 
 * left bottom and right top corner 
 * 
 * @author evgeni
 *
 */
public class CRectangle 
{
	/***************************************************/
	/****** C'tors *************************************/
	/***************************************************/
	public CRectangle()
	{
		setLayer(Layer.None);
		setID(0);
		
		setLeftEdge(new CEdge(0, 0, 0, 0, 0, this));
		setRightEdge(new CEdge(0, 0, 0, 0, 0, this));
		setTopEdge(new CEdge(0, 0, 0, 0, 0, this));
		setBottomEdge(new CEdge(0, 0, 0, 0, 0, this));
	}
	
	public CRectangle(int xLeft, int yLeft, int xRight, int yRight, Layer layer, long id)
	{
		setLayer(layer);
		setID(id);
		
		setLeftEdge(new CEdge(xLeft, yLeft, xLeft, yRight, id, this));
		setRightEdge(new CEdge(xRight, yRight, xRight, yLeft, id, this));
		setTopEdge(new CEdge(xLeft, yRight, xRight, yRight, id, this));
		setBottomEdge(new CEdge(xRight, yLeft, xLeft, yLeft, id, this)); 
	}
	
	
	/***************************************************/
	/****** Members ************************************/
	/***************************************************/	
	private Layer m_layer;
	
	private long m_id;
	
	private String m_name;
	
	private CEdge m_leftEdge;
	private CEdge m_rightEdge;
	private CEdge m_topEdge;
	private CEdge m_bottomEdge;
	
	
	/***************************************************/
	/****** Getters / Setters **************************/
	/***************************************************/
	public Layer getLayer() {
		return m_layer;
	}
	public void setLayer(Layer m_layer) {
		this.m_layer = m_layer;
	}
	
	public long getID() {
		return m_id;
	}
	public void setID(long id) {
		this.m_id = id;
	}
	
	public String getName() {
		return m_name;
	}
	public void setName(String name) {
		this.m_name = name;
	}
	
	public CEdge getLeftEdge() {
		return m_leftEdge;
	}
	public void setLeftEdge(CEdge edge) {
		m_leftEdge = edge;
	}
	public CEdge getRightEdge() {
		return m_rightEdge;
	}
	public void setRightEdge(CEdge edge) {
		m_rightEdge = edge;
	}
	public CEdge getTopEdge() {
		return m_topEdge;
	}
	public void setTopEdge(CEdge edge) {
		m_topEdge = edge;
	}
	public CEdge getBottomEdge() {
		return m_bottomEdge;
	}
	public void setBottomEdge(CEdge edge) {
		m_bottomEdge = edge;
	}
	
	public int getWidth()
	{
		return Math.abs(getTopEdge().getStartPoint().x - getTopEdge().getEndPoint().x);
	}
	public int getLength()
	{
		return Math.abs(getLeftEdge().getStartPoint().y - getLeftEdge().getEndPoint().y);
	}	
	public Point getCenter()
	{
		return new Point(
				(int)(m_rightEdge.getStartPoint().x + m_leftEdge.getStartPoint().x)/2,
				(int)(m_topEdge.getStartPoint().y + m_bottomEdge.getStartPoint().y)/2);
	}
	
	
	/***************************************************/
	/****** Public Methods ***************************/
	/***************************************************/
	
	/**
	 * The order of the returned edges is:
	 * Left bottom corner first, and others by clock direction 
	 */
	public ArrayList<CEdge> getAllEdges()
	{
		ArrayList<CEdge> allEdges = new ArrayList<CEdge>(4);
		
		allEdges.add(0, getLeftEdge());
		allEdges.add(1, getTopEdge());
		allEdges.add(2, getRightEdge());
		allEdges.add(3, getBottomEdge());
		
		return allEdges;
	}
	
	public long getPerimeter()
	{
		long perimeter = 0;
		ArrayList<CEdge> allEdges = this.getAllEdges();
		
		for (int i = 0; i < allEdges.size(); i++) 
			perimeter +=  allEdges.get(i).GetLength();
		
		return perimeter;
	}
	
	public long getArea()
	{ 
		return this.getLeftEdge().GetLength() * this.getTopEdge().GetLength();
	}
	
	public boolean isIntersecting(CRectangle rec)
	{
		if(
				rec.getLeftEdge().getStartPoint().x < this.getRightEdge().getStartPoint().x && 
				rec.getRightEdge().getStartPoint().x > this.getLeftEdge().getStartPoint().x &&
				rec.getBottomEdge().getStartPoint().y < this.getTopEdge().getStartPoint().y &&
				rec.getTopEdge().getStartPoint().y > this.getBottomEdge().getStartPoint().y
			)
				return true; 
		
		return false;
	}
	
	public boolean isInnerPoint(Point point)
	{
		if(
				point.x > m_leftEdge.getStartPoint().x 
				&& point.x < m_rightEdge.getStartPoint().x
				&& point.y > m_bottomEdge.getStartPoint().y
				&& point.y < m_topEdge.getStartPoint().y
		)
			return true;
		
		return false;
	}
	
	//Override
	public String toString()
	{
		if(m_id < 0)
			return new String(
					m_leftEdge.getStartPoint().x +
					" " +
					m_leftEdge.getStartPoint().y + 
					" , " + 
					m_rightEdge.getStartPoint().x + 
					" " + 
					m_rightEdge.getStartPoint().y);
		
		return new String(
				m_leftEdge.getStartPoint().x +
				" " +
				m_leftEdge.getStartPoint().y + 
				" , " + 
				m_rightEdge.getStartPoint().x + 
				" " + 
				m_rightEdge.getStartPoint().y + 
				" : " +
				m_id);
	}
	
	public boolean equals(CRectangle rec)
	{
		if(
				m_leftEdge.getStartPoint().x == rec.getLeftEdge().getStartPoint().x 
				&& m_leftEdge.getStartPoint().y == rec.getLeftEdge().getStartPoint().y
				&& m_rightEdge.getStartPoint().x == rec.getRightEdge().getStartPoint().x 
				&& m_rightEdge.getStartPoint().y == rec.getRightEdge().getStartPoint().y
			)
			return true;
		
		return false;
	}

	/***************************************************/
	/****** Utils **************************************/
	/***************************************************/
	/**
	 * Returns true if recA fits in recB
	 */
	public static boolean recFits(CRectangle recA , CRectangle recB) {
		long deltaXA  = Math.abs(recA.getLeftEdge().getStartPoint().x - recA.getRightEdge().getStartPoint().x);
		long deltaYA  = Math.abs(recA.getBottomEdge().getStartPoint().y - recA.getTopEdge().getStartPoint().y);
		long deltaXB  = Math.abs(recB.getLeftEdge().getStartPoint().x - recB.getRightEdge().getStartPoint().x);
		long deltaYB  = Math.abs(recB.getBottomEdge().getStartPoint().y - recB.getTopEdge().getStartPoint().y);
		
		if (deltaXA<=deltaXB && deltaYA<=deltaYB) return true;
		
		return false;
		
	}
	
	public Point getBottomLeftPoint() {
		return this.getLeftEdge().getStartPoint();
	}
	
	public Point getTopRightPoint() {
		return this.getRightEdge().getStartPoint();
	}
	
	//edge to edge distance
	public static int absDistanceE2Ehor (CRectangle r1, CRectangle r2) {
		int x1b = r1.getLeftEdge().getStartPoint().x;
		int x1e = r1.getRightEdge().getStartPoint().x;
		int x2b = r2.getLeftEdge().getStartPoint().x;
		int x2e = r2.getRightEdge().getStartPoint().x;
	
		
		if ( x1e < x2b ) {
			return Math.abs(x1e-x2b);
		}
		if ( x2e < x1b ) {
			return Math.abs(x2e-x1b);
		}
		return 0;
		
	}
	public static int absDistanceE2Ever (CRectangle r1, CRectangle r2) {
		int y1b = r1.getBottomEdge().getStartPoint().y;
		int y1e = r1.getTopEdge().getStartPoint().y;
		int y2b = r2.getBottomEdge().getStartPoint().y;
		int y2e = r2.getTopEdge().getStartPoint().y;
	
		
		if ( y1e < y2b ) {
			return Math.abs(y1e-y2b);
		}
		if ( y2e < y1b ) {
			return Math.abs(y2e-y1b);
		}
		return 0;
		
	}
	public static void printRecsList (LinkedList<CRectangle> recs) {
		for (CRectangle rec : recs) {
			printRectangle(rec);
		}
	}
	public static void printRectangle(CRectangle r) {
		System.out.println("["+r.getLeftEdge().getStartPoint().x+","+r.getLeftEdge().getStartPoint().y+":"+r.getRightEdge().getStartPoint().x+","+r.getRightEdge().getStartPoint().y+"]");
	}

}
